package com.zatech.cgnci.project.base.utils;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;

/**
 * @author EDY
 * @version 1.0
 */
public class BeanUtils {
    /**
     * 对list的某个int属性求和
     *
     * @param list
     * @param property 属性get方法
     * @param <T>
     * @return
     */
    public static <T> int sumIntProperty(List<T> list, Function<? super T, Integer> property) {
        return list.stream().mapToInt(property::apply).sum();
    }

    /**
     * 对list的某个double属性求和
     *
     * @param list
     * @param property 属性get方法
     * @param <T>
     * @return
     */
    public static <T> double sumDoubleProperty(List<T> list, Function<? super T, Double> property) {
        return list.stream().mapToDouble(property::apply).sum();
    }

    /**
     * 对list的某个long属性求和
     *
     * @param list
     * @param property 属性get方法
     * @param <T>
     * @return
     */
    public static <T> Long sumLongProperty(List<T> list, Function<? super T, Long> property) {
        return list.stream().mapToLong(property::apply).sum();
    }

    /**
     * 对list的某个BigDecimal属性求和
     *
     * @param list
     * @param property 属性get方法
     * @param <T>
     * @return
     */
    public static <T> BigDecimal sumBigDecimalProperty(List<T> list, Function<? super T, BigDecimal> property) {
        return list.stream().map(property).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 对list的多个属性求和
     *
     * @param list
     * @param properties 属性名集
     * @param <T>
     * @return 返回Map
     */
    public static <T> Map<String, Object> sumProperties(List<T> list, String... properties) throws NoSuchMethodException {
        Map<String, Function<T, Object>> propertyMap = getPropertyFunctionMap(list, properties);

        Map<String, Object> result = new HashMap<>();
        for (String property : properties) {
            if (propertyMap.containsKey(property)) {
                Function<T, Object> function = propertyMap.get(property);
                Object sum = list.stream().map(function).reduce(null, (a, b) -> {
                    return getSum(property, a, b);
                });
                result.put(property, sum);
            }
        }
        return result;
    }

    /**
     * 对list的多个属性求和
     *
     * @param list
     * @param properties 属性名集
     * @param <T>
     * @return 返回实体对象
     */
    public static <T> T sumObjProperties(List<T> list, String... properties) throws NoSuchMethodException {
        Map<String, Function<T, Object>> propertyMap = getPropertyFunctionMap(list, properties);

        Class clazz = list.get(0).getClass();
        T result = (T) createNewInstance(clazz);

        for (String property : properties) {
            if (propertyMap.containsKey(property)) {
                Function<T, Object> function = propertyMap.get(property);
                Object sum = list.stream().map(function).reduce(null, (a, b) -> {
                    return getSum(property, a, b);
                });

                // 设置求和结果给新对象的对应属性
                try {
                    Method setterMethod =
                            clazz.getMethod("set" + property.substring(0, 1).toUpperCase() + property.substring(1),
                                    sum.getClass());
                    setterMethod.invoke(result, sum);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    private static Object getSum(String property, Object a, Object b) {
        if (a == null) {
            return b;
        } else if (b == null) {
            return a;
        } else if (a instanceof Integer) {
            return (int) a + (int) b;
        } else if (a instanceof BigDecimal) {
            return ((BigDecimal) a).add((BigDecimal) b);
        } else {
            throw new IllegalArgumentException("不支持的属性计算类型:" + property);
        }
    }

    private static <T> Map<String, Function<T, Object>> getPropertyFunctionMap(List<T> list, String[] properties) throws NoSuchMethodException {
        Map<String, Function<T, Object>> propertyMap = new HashMap<>();
        Class<?> clazz = list.get(0).getClass();
        for (String property : properties) {
            Method method = clazz.getMethod("get" + property.substring(0, 1).toUpperCase() + property.substring(1));
            Class<?> returnType = method.getReturnType();
            if (returnType == Integer.class || returnType == int.class) {
                propertyMap.put(property, (Function<T, Object>) value -> {
                    try {
                        return method.invoke(value);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                });
            } else if (returnType == BigDecimal.class) {
                propertyMap.put(property, (Function<T, Object>) value -> {
                    try {
                        return method.invoke(value);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                });
            } else {
                throw new IllegalArgumentException("Unsupported type for " + property);
            }
        }
        return propertyMap;
    }

    private static <T> T createNewInstance(Class<T> clazz) {
        try {
            return clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getUUID() {

        return UUID.randomUUID().toString().replace("-", "");
    }

    public static String getFirstValue(String input) {
        if (VerifyUtils.isEmpty(input)) {
            return input;
        }
        int commaIndex = input.indexOf(',');
        return commaIndex == -1 ? input.trim() : input.substring(0, commaIndex).trim();
    }

}
